/*
 * Copyright 2011-2012 Rivoli team
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.googlecode.rivoli.reader.aluminum

import com.googlecode.aluminumproject.parsers.aluscript.AluScriptParser
import com.googlecode.rivoli.RivoliException
import com.googlecode.rivoli.model.Element
import com.googlecode.rivoli.model.support.ElementDescriptorSupport
import com.googlecode.rivoli.model.support.ModelSupport
import com.googlecode.rivoli.reader.DefinitionReader

import org.testng.annotations.Test

class AluminumDefinitionReaderTest {
	@Test
	void 'a definition should have an element'() {
		Element element = createDefinitionReader().read('definitions/letter.alu', new LetterModel(), [:])

		assert element.descriptor.name == 'letter'
	}

	@Test
	void 'definitions should be includable'() {
		Element element = createDefinitionReader().read('definitions/include_letter.alu', new LetterModel(), [:])

		assert element.descriptor.name == 'letter'
	}

	@Test(expectedExceptions = RivoliException)
	void 'definitions should not be empty'() {
		createDefinitionReader().read('definitions/empty.alu', new LetterModel(), [:])
	}

	@Test(expectedExceptions = RivoliException)
	void 'a definition should not have more than one element'() {
		createDefinitionReader().read('definitions/letters.alu', new LetterModel(), [:])
	}

	@Test
	void 'parameters should be mapped to attributes'() {
		Element element = createDefinitionReader().read('definitions/addressed_letter.alu', new LetterModel(), [:])

		assert element.attributes['addressee'] == 'Santa Claus'
	}

	@Test(expectedExceptions = RivoliException)
	void 'unknown parameters should not be allowed'() {
		createDefinitionReader().read('definitions/signed_letter.alu', new LetterModel(), [:])
	}

	@Test
	void 'a definition should support nested elements'() {
		Element element = createDefinitionReader().read('definitions/letter_with_content.alu', new LetterModel(), [present: 'bike'])

		assert element.descriptor.name == 'letter'
		assert element.children.size() == 1

		Element child = element.children.first()

		assert child.descriptor.name == 'body'
		assert child.attributes['text'] == 'I would like a bike'
	}

	private DefinitionReader createDefinitionReader() {
		DefinitionReader definitionReader = new AluminumDefinitionReader()
		definitionReader.init([:])
		definitionReader
	}

	@Test
	void 'parser should be configurable'() {
		DefinitionReader definitionReader = new AluminumDefinitionReader()
		definitionReader.init((AluminumDefinitionReader.PARSER): 'xml')

		Element element = definitionReader.read('definitions/letter.xml', new LetterModel(), [:])

		assert element.descriptor.name == 'letter'
	}

	@Test
	void 'definition reader should be configurable'() {
		DefinitionReader definitionReader = new AluminumDefinitionReader()
		definitionReader.init((AluminumDefinitionReader.ALUMINUM_PARAMETERS): [(AluScriptParser.TEMPLATE_EXTENSION): 'alu'])

		Element element = definitionReader.read('definitions/letter', new LetterModel(), [:])

		assert element.descriptor.name == 'letter'
	}

	private static class LetterModel extends ModelSupport {
		LetterModel() {
			ElementDescriptorSupport body = new ElementDescriptorSupport('body')
			body.addAttributeDescriptor('text', String)

			ElementDescriptorSupport letter = new ElementDescriptorSupport('letter')
			letter.addAttributeDescriptor('addressee', String)
			letter.setContainerFor(body)

			addElementDescriptor(letter)
			addElementDescriptor(body)
		}
	}
}